package info.ms.neural.flowrate.core;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import info.ms.neural.common.utils.StringUtils;
import info.ms.neural.flowrate.IFlowrate;
import info.ms.neural.flowrate.entity.FlowrateRule;
import info.ms.neural.flowrate.ratelimiter.NIORateLimiterFlowrate;
import info.ms.neural.flowrate.runner.IFlowrateRunner;
import info.ms.neural.flowrate.semaphore.NIOSemaphoreFlowrate;

/**
 * 限流
 * <br>
 * 并发数<br>
 * QPS:每秒钟、每分钟、每小时、每一天的<br>
 * <br>
 * @author lry
 *
 * @param <REQ>
 * @param <RES>
 */
public class FlowrateFactory<REQ, RES> implements IFlowrate<REQ, RES> {

	/**
	 * 流控规则
	 */
	private final ConcurrentHashMap<String, FlowrateRule> flowrateRuleMap = new ConcurrentHashMap<String, FlowrateRule>();
	/**
	 * QPS流控
	 */
	private final ConcurrentHashMap<String, NIORateLimiterFlowrate<REQ, RES>> nioRateLimiterFlowrateMap = new ConcurrentHashMap<String, NIORateLimiterFlowrate<REQ, RES>>();
	/**
	 * 并发流控
	 */
	private final ConcurrentHashMap<String, NIOSemaphoreFlowrate<REQ, RES>> nioSemaphoreFlowrateMap = new ConcurrentHashMap<String, NIOSemaphoreFlowrate<REQ, RES>>();
	
	
	public FlowrateFactory(List<FlowrateRule> flowrateRules) {
		if(flowrateRules==null){
			return;
		}
		
		for (FlowrateRule flowrateRule:flowrateRules) {
			flowrateRuleMap.put(flowrateRule.getKey(), flowrateRule);
		}
	}
	
	/**
	 * 初始化
	 */
	public void init() throws Throwable {
		
	}

	/**
	 * 流控
	 */
	public RES flowrate(final String flowrateId, REQ req, final IFlowrateRunner<REQ, RES> runner) throws Throwable {
		if(flowrateId==null || req==null || StringUtils.isBlank(flowrateId)){//忽略非法请求的流控
			return runner.runner(req);
		}
		
		try {
			final FlowrateRule flowrateRule=flowrateRuleMap.get(flowrateId);
			if(flowrateRule!=null){//为空则不需要流控
				switch (flowrateRule.getFlowrateType()) {
				case CCT:{
					return cct(flowrateId, flowrateRule, runner, req);
				} case QPS:{
					return qps(flowrateId, flowrateRule, runner, req);
				} case QPS_CCT:{
					return cct(flowrateId, flowrateRule, new IFlowrateRunner<REQ, RES>(){
						public RES runner(REQ req) throws Throwable {
							return qps(flowrateId, flowrateRule, runner, req);
						}
					}, req);
				}default:
					break;
				}
			}
		} catch (Throwable t) {
			t.printStackTrace();
		}
		throw new RuntimeException("流控异常");
	}
	
	/**
	 * 并发控制
	 * 
	 * @param flowrateId
	 * @param flowrateRule
	 * @param runner
	 * @param req
	 * @return
	 * @throws Throwable
	 */
	private RES cct(String flowrateId, FlowrateRule flowrateRule, IFlowrateRunner<REQ, RES> runner, REQ req) throws Throwable {
		NIOSemaphoreFlowrate<REQ, RES> nioSemaphoreFlowrate=nioSemaphoreFlowrateMap.get(flowrateId);
		if(nioSemaphoreFlowrate==null){
			nioSemaphoreFlowrate=new NIOSemaphoreFlowrate<REQ, RES>(flowrateRule);
		}
		return nioSemaphoreFlowrate.semaphore(req, runner);
	}
	
	/**
	 * QPS控制
	 * 
	 * @param flowrateId
	 * @param flowrateRule
	 * @param runner
	 * @param req
	 * @return
	 * @throws Throwable
	 */
	private RES qps(String flowrateId, FlowrateRule flowrateRule, IFlowrateRunner<REQ, RES> runner, REQ req) throws Throwable {
		NIORateLimiterFlowrate<REQ, RES> nioRateLimiterFlowrate=nioRateLimiterFlowrateMap.get(flowrateId);
		if(nioRateLimiterFlowrate==null){
			nioRateLimiterFlowrate=new NIORateLimiterFlowrate<REQ, RES>(flowrateRule);
		}
		boolean rateLimiterCheck=nioRateLimiterFlowrate.rateLimiter();//QPS流控校验器
		if(rateLimiterCheck){//放通
			return runner.runner(req);
		}else{//QPS拒绝
			throw new RuntimeException("QPS流控拒绝");
		}
	}

	/**
	 * 销毁
	 */
	public void destory() throws Throwable {
		
	}

}
